package com.hhf.rpc.core.proxy;

import cn.hutool.core.collection.CollUtil;
import com.hhf.rpc.core.RpcApplication;
import com.hhf.rpc.core.config.RegistryConfig;
import com.hhf.rpc.core.config.RpcConfig;
import com.hhf.rpc.core.constant.RpcConstant;
import com.hhf.rpc.core.fault.loadbalancer.LoadBalancer;
import com.hhf.rpc.core.fault.loadbalancer.LoadBalancerFactory;
import com.hhf.rpc.core.fault.tolerant.TolerantStrategy;
import com.hhf.rpc.core.fault.tolerant.TolerantStrategyFactory;
import com.hhf.rpc.core.model.RpcRequest;
import com.hhf.rpc.core.model.RpcResponse;
import com.hhf.rpc.core.model.ServiceMetaInfo;
import com.hhf.rpc.core.registry.Registry;
import com.hhf.rpc.core.registry.RegistryFactory;
import com.hhf.rpc.core.retry.RetryStrategy;
import com.hhf.rpc.core.retry.RetryStrategyFactory;
import com.hhf.rpc.core.serializer.Serializer;
import com.hhf.rpc.core.serializer.SerializerFactory;
import com.hhf.rpc.core.client.impl.VertxTcpClient;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author hhf
 * @Date 2024/10/15
 * @Description
 */
@Slf4j
public class ServiceProxy implements InvocationHandler {

//    private static final String BASE_URL = "http://localhost:8080";

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //0.指定序列化器
        RpcConfig rpcConfig = RpcApplication.getRpcConfig();

        String serializerKey = rpcConfig.getSerializerKey();
        Serializer serializer = SerializerFactory.getSerializerInstance(serializerKey);

        //1.构造请求对象RpcReqeust
        String serviceName = method.getDeclaringClass().getName();
        RpcRequest rpcRequest = RpcRequest.builder()
                .serviceName(serviceName)
                .methodName(method.getName())
                .args(args)
                .parameterTypes(method.getParameterTypes())
                .build();

        try {
            //2.序列化请求对象 RpcReqeust -> byte[]
            //byte[] bytes = serializer.serialize(rpcRequest);
            //3.发送请求,获取响应数据 byte[]  ===> 改造为从 注册中心 获取请求地址,发送请求
            //3.1从Rpc中获取Registry的配置
            RegistryConfig registryConfig = rpcConfig.getRegistryConfig();
            //3.2获取请求服务key
            String serviceKey = registryConfig.getRegistry();
            //3.3获取实例对象
            Registry registry = RegistryFactory.getRegistry(serviceKey);
            //3.4构造请求结点
            ServiceMetaInfo serviceMetaInfo = new ServiceMetaInfo();
            serviceMetaInfo.setServiceName(serviceName);
            serviceMetaInfo.setServiceVersion(RpcConstant.DEFAULT_SERVICE_VERSION);
            //3.5发现服务
            List<ServiceMetaInfo> serviceMetaInfoList = registry.serviceDiscovery(serviceMetaInfo.getServiceKey());
            if (CollUtil.isEmpty(serviceMetaInfoList)){
                throw new RuntimeException("暂无服务地址");
            }

            //使用默认的负载均衡器(轮询)
            LoadBalancer loadBalancer = LoadBalancerFactory.getInstance(rpcConfig.getLoadBalancerKey());
            Map<String,Object> requestParams = new HashMap<>();
            requestParams.put("methodName",rpcRequest.getMethodName());
            ServiceMetaInfo selectServiceMetaInfo = loadBalancer.select(requestParams, serviceMetaInfoList);



            String address = selectServiceMetaInfo.getServiceAddress();
            log.info("正在发送请求至{},使用的序列化器为:{}",address,serializer.getClass().getName());

            //由http协议,改为自定义协议
//            HttpResponse httpResponse = HttpRequest.post(address)
//                    .body(bytes)
//                    .execute();
            //rpc请求
            //重试机制
            RpcResponse rpcResponse = null;
            try {
                RetryStrategy retryStrategy = RetryStrategyFactory.getInstance(rpcConfig.getRetryStrategyKey());
                rpcResponse = retryStrategy.doRetry(() -> VertxTcpClient.doRequest(selectServiceMetaInfo, rpcRequest));
            } catch (Exception e) {
                log.error("出现错误,执行容错机制:{}",e);
                //容错处理
                TolerantStrategy tolerantStrategy = TolerantStrategyFactory.getInstance(rpcConfig.getTolerantStrategyKey());
                rpcResponse = tolerantStrategy.doTolerant(null, e);
            }

            //4.反序列化,构造响应对象 byte[] -> RpcResponse
//            byte[] bodyBytes = httpResponse.bodyBytes();
//            RpcResponse rpcResponse = serializer.deSerialize(bodyBytes, RpcResponse.class);
            //5.返回数据
            return rpcResponse.getData();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


}
